using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using PluginHandler.Database;
using Npgsql;

namespace NpgsqlPlugin.Database
{
    class DatabaseHandler : IDatabaseHandler
    {
        public event ScriptProcessedEventHandler ScriptProcessed;

        private DbConnectionStringBuilder _configuration;
        private DatabaseStructure _databaseStructure;
        private IDbConnection _databaseConnection;

        internal DatabaseHandler()
        { 
        }

        #region IDatabaseHandler Member

        public void LoadDatabase(DbConnectionStringBuilder configuration)
        {
            _configuration = configuration;
            ReloadDatabase();
        }

        public void ReloadDatabase()
        {
            if (_configuration != null)
            {
                try
                {
                    _databaseConnection = new NpgsqlConnection(_configuration.ConnectionString);

                    _databaseConnection.Open();
                    _databaseStructure = new DatabaseStructure(this);
                }
                //Exception must be wrapped and forwarded, cause NpgsqlException doesn't inherit from DbException class
                catch (NpgsqlException ex)
                {
                    throw new NpgsqlExceptionWrapperException(ex);
                }
            }
            else
            {
                throw new Exception("Database is not loaded!");
            }
        }

        public void UnloadDatabase()
        {
            if (_configuration != null)
            {
                //closes the connection, if it is not closed
                if(_databaseConnection.State != ConnectionState.Closed)
                    _databaseConnection.Close();

                //set all variables to null
                _configuration = null;
                _databaseStructure = null;
                _databaseConnection = null;
            }
        }

        public DbConnectionStringBuilder CreateConnectionStringWithPassword(DbConnectionStringBuilder connectionStringDetails, string password)
        {
            DbConnectionStringBuilder connectionStringBuilder = new DbConnectionStringBuilder();
            connectionStringBuilder.ConnectionString = connectionStringDetails.ConnectionString;

            connectionStringBuilder.Remove("Password");
            connectionStringBuilder.Add("Password", password);

            return connectionStringBuilder;
        }

        public IDatabaseStructure DatabaseStructure
        {
            get 
            {
                return _databaseStructure;
            }
        }

        public void ExecuteNonQuery(string commandText)
        {
            NpgsqlCommand command = ((NpgsqlConnection)_databaseConnection).CreateCommand();
            command.CommandText = commandText;
            command.ExecuteNonQuery();
        }

        public IDataReader ExecuteReader(string commandText)
        {
            NpgsqlCommand command = ((NpgsqlConnection)_databaseConnection).CreateCommand();
            command.CommandText = commandText;
            return command.ExecuteReader();
        }

        public object ExecuteScalar(string commandText)
        {
            NpgsqlCommand command = ((NpgsqlConnection)_databaseConnection).CreateCommand();
            command.CommandText = commandText;
            return command.ExecuteScalar();
        }

        public void ExecuteDatabaseScript(string scriptSource)
        {
            ExecuteNonQuery(scriptSource);
        }

        public IDbConnection DatabaseConnection
        {
            get 
            {
                return _databaseConnection;
            }
        }

        public DbConnectionStringBuilder ConnectionStringDetails
        {
            get 
            {
                return _configuration;
            }
        }

        public string DelimitedIdentifierBegin
        {
            get { return "\""; }
        }

        public string DelimitedIdentifierEnd
        {
            get { return "\""; }
        }
        #endregion
    }
}
